package com.iisigroup.streetblock.service.impl;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.iisigroup.streetblock.common.service.GenericService;
import com.iisigroup.streetblock.service.StreetBlockService;
import com.iisigroup.streetblock.vo.StreetBlockVO;


/**
 * 街廓的Service實作
 * @author Ebi
 * @since 2015/01/13
 */
@Service
public class StreetBlockServiceImpl extends GenericService implements StreetBlockService {
	private static final Integer BUFFER_SIZE = 32768;
	private static final String ERROR_MSG = "ERROR!";
	
	
	//特殊道路的起始編號
	private Integer specialNum = 9999;
	//用來儲存特殊道路的map
	private Map<String, String> specialMap = new HashMap<String, String>();

	@Override
	public List<StreetBlockVO> readFile(String url, String encoding) {
		List<StreetBlockVO> result = new ArrayList<StreetBlockVO>();
		Set<StreetBlockVO> set = new HashSet<StreetBlockVO>();
		File file = new File(url);
		
		//例外檔的位置
		String path = url.substring(0, url.lastIndexOf("/"));
		File exception = new File(path + "/例外資料/例外.txt");
		exception.getParentFile().mkdirs();
		
		BufferedReader br = null;
		BufferedWriter bw = null;
		String line = null;
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding), BUFFER_SIZE);
			bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(exception), encoding), BUFFER_SIZE);
			Integer count = 0;
			while ((line = br.readLine()) != null) {
				count++;
				StreetBlockVO vo = this.stripLine(line);
				if (!StringUtils.isEmpty(vo.getAdm())) {
					set.add(vo);
				} else {
					//如果沒有行政編號，代表轉換失敗，則寫入到例外檔
					String msg = "第" + count + "筆資料轉換失敗...";
					log.debug(msg + line);
					bw.write(msg);
					bw.newLine();
					bw.write(line);
					bw.newLine();
				}
			}
		} catch (UnsupportedEncodingException e) {
			log.error(ERROR_MSG, e);
		} catch (FileNotFoundException e) {
			log.error(ERROR_MSG, e);
		} catch (IOException e) {
			log.error(ERROR_MSG, e);
		} finally {
			try {
				if (br != null) {
					br.close();
				}
				if (bw != null) {
					bw.close();
				}
			} catch (IOException e) {
				log.error(ERROR_MSG, e);
			}
		}
		result.addAll(set);
		return result;
	}
	
	@Override
	public StreetBlockVO stripLine(String line) {
		//編碼
		final String encoding = "MS950";
		final Integer admBgn = 328;
		final Integer admEnd = 338;
		final Integer countyBgn = 113;
		final Integer countyEnd = 119;
		final Integer cityBgn = 119;
		final Integer cityEnd = 127;
		final Integer vilBgn = 127;
		final Integer vilEnd = 135;
		final Integer rdBgn = 135;
		final Integer rdEnd = 153;
		final Integer neigBgn = 7;
		final Integer neigEnd = 10;
		final Integer secBgn = 153;
		final Integer secEnd = 165;
		final Integer lanBgn = 167;
		final Integer lanEnd = 183;
		final Integer alyBgn = 185;
		final Integer alyEnd = 197;
		final Integer sAlyBgn = 199;
		final Integer sAlyEnd = 207;
		final Integer numBgn = 213;
		final Integer numEnd = 221;
				
		StreetBlockVO result = new StreetBlockVO();
		try {
			//以byte數取得定長資料
			byte[] bytes = line.getBytes(encoding);
			//行政編號
			String adm = new String(Arrays.copyOfRange(bytes, admBgn, admEnd), encoding);
			//縣(市)
			String county = new String(Arrays.copyOfRange(bytes, countyBgn, countyEnd), encoding);
			//(市)鄉鎮區
			String city = new String(Arrays.copyOfRange(bytes, cityBgn, cityEnd), encoding);
			//里(村)
			String village = new String(Arrays.copyOfRange(bytes, vilBgn, vilEnd), encoding);
			//路
			String road = new String(Arrays.copyOfRange(bytes, rdBgn, rdEnd), encoding);
			//鄰
			String neighborhood = adm.substring(neigBgn, neigEnd);
			
			//段(中文)
			String sectionCh = new String(Arrays.copyOfRange(bytes, secBgn, secEnd), encoding);
			//巷(中文)
			String laneCh = new String(Arrays.copyOfRange(bytes, lanBgn, lanEnd), encoding);
			//弄(中文)
			String alleyCh = new String(Arrays.copyOfRange(bytes, alyBgn, alyEnd), encoding);
			//衖(中文)
			String subAlleyCh = new String(Arrays.copyOfRange(bytes, sAlyBgn, sAlyEnd), encoding);
			//段
			String section = this.formatChineseNumber(this.trim(sectionCh));
			//巷
			String lane = this.parseNumber(laneCh);
			//弄
			String alley = this.parseNumber(alleyCh);
			//衖
			String subAlley = this.parseNumber(subAlleyCh);
			//號
			String numero = this.parseNumber(new String(Arrays.copyOfRange(bytes, numBgn, numEnd), encoding));
			//是否為特殊地址
			if (this.hasSpecial(laneCh)) {
				if (!this.specialMap.containsKey(laneCh)) {
					this.specialMap.put(laneCh, this.specialNum.toString());
					lane = this.specialNum.toString();
					this.specialNum--;
				} else {
					lane = this.specialMap.get(laneCh);
				}
			}
			
			if (this.hasSpecial(alleyCh)) {
				if (!this.specialMap.containsKey(alleyCh)) {
					this.specialMap.put(alleyCh, this.specialNum.toString());
					alley = this.specialNum.toString();
					this.specialNum--;
				} else {
					alley = this.specialMap.get(alleyCh);
				}
			}
			
			if (this.hasSpecial(subAlleyCh)) {
				if (!this.specialMap.containsKey(subAlleyCh)) {
					this.specialMap.put(subAlleyCh, this.specialNum.toString());
					subAlley = this.specialNum.toString();
					this.specialNum--;
				} else {
					subAlley = this.specialMap.get(subAlleyCh);
				}
			}
			
			Integer oddAndEven = this.checkOddAndEven(this.convertToInteger(numero));
			Long weight = 0L;
			//計算權重
			if (this.convertToInteger(lane) != 0) {
				//如果有巷
				weight += 1000000000000000000L * this.checkOddAndEven(this.convertToInteger(lane)) + //巷單雙
						1000000000000000000L / 10000 * this.convertToInteger(lane); //巷
				if (this.convertToInteger(alley) != 0) {
					//如果有弄
					weight += 1000000000000000000L / 10000 / 10 * this.checkOddAndEven(this.convertToInteger(alley)) + //弄單雙
							1000000000000000000L / 10000 / 10 / 10000 * this.convertToInteger(alley); //弄
					if (this.convertToInteger(subAlley) != 0) {
						//如果有衖
						weight += 1000000000000000000L / 10000 / 10 / 10000 / 10 * this.checkOddAndEven(this.convertToInteger(subAlley)) + //衖單雙
								1000000000000000000L / 10000 / 10 / 10000 / 10 / 10000 * this.convertToInteger(subAlley) + //衖
								1000000000000000000L / 10000 / 10 / 10000 / 10 / 10000 / 10 * oddAndEven + //號單雙
								1000000000000000000L / 10000 / 10 / 10000 / 10 / 10000 / 10 / 1000 * this.convertToInteger(numero); //號
					} else {
						//如果沒有衖
						weight += 1000000000000000000L / 10000 / 10 / 10000 / 10 * oddAndEven + //號單雙
								1000000000000000000L / 10000 / 10 / 10000 / 10 / 10000 * this.convertToInteger(numero); //號
								
					}
				} else {
					//如果沒有弄
					if (this.convertToInteger(subAlley) != 0) {
						//如果有衖
						weight += 1000000000000000000L / 10000 / 10 * this.checkOddAndEven(this.convertToInteger(subAlley)) + //衖單雙
								1000000000000000000L / 10000 / 10 / 10000 * this.convertToInteger(subAlley) + //衖
								  1000000000000000000L / 10000 / 10 / 10000 / 10 *  oddAndEven + //號單雙
								  1000000000000000000L / 10000 / 10 / 10000 / 10 / 10000 * this.convertToInteger(numero); //號
					} else {
						//如果沒有衖
						weight += 1000000000000000000L / 10000 / 10 * oddAndEven + //號單雙
								1000000000000000000L / 10000 / 10 / 10000 * this.convertToInteger(numero); //號
					}
					
				}
			} else {
				//如果沒巷
				if (this.convertToInteger(alley) != 0) {
					//如果有弄
					weight += 1000000000000000000L * this.checkOddAndEven(this.convertToInteger(alley)) + //弄單雙
							1000000000000000000L / 10000 * this.convertToInteger(alley); //弄
					if (this.convertToInteger(subAlley) != 0) {
						//如果有衖
						weight += 1000000000000000000L / 10000 / 10 * this.checkOddAndEven(this.convertToInteger(subAlley)) + //衖單雙
								1000000000000000000L / 10000 / 10 / 10000 * this.convertToInteger(subAlley) + //衖
								  1000000000000000000L / 10000 / 10 / 10000 / 10 * oddAndEven + //號單雙
								  1000000000000000000L / 10000 / 10 / 10000 / 10 / 10000 * this.convertToInteger(numero); //號
					} else {
						//如果沒有衖
						weight += 1000000000000000000L / 10000 / 10 * oddAndEven + //號單雙
								1000000000000000000L / 10000 / 10 / 10000 * this.convertToInteger(numero); //號
					}
				} else {
					//如果沒有弄
					if (this.convertToInteger(subAlley) != 0) {
						//如果有衖
						weight += 1000000000000000000L * this.checkOddAndEven(this.convertToInteger(subAlley)) + //衖單雙
								1000000000000000000L / 10000 * this.convertToInteger(subAlley) + //衖
								   1000000000000000000L / 10000 / 10 * oddAndEven + //號單雙
								   1000000000000000000L / 10000 / 10 / 10000 * this.convertToInteger(numero); //號
					} else {
						//如果沒有衖
						weight += 1000000000000000000L * oddAndEven + //號單雙
								1000000000000000000L / 10000 * this.convertToInteger(numero); //號
					}
				}
				
			}
			
			result.setAdm(adm);
			result.setCounty(county);
			result.setCity(city);
			result.setVillage(village);
			result.setNeighborhood(neighborhood);
			result.setRoad(road);
			result.setSection(section);
			result.setSectionCh(sectionCh);
			result.setLane(lane);
			result.setLaneCh(laneCh);
			result.setAlley(alley);
			result.setAlleyCh(alleyCh);
			result.setSubAlley(subAlley);
			result.setSubAlleyCh(subAlleyCh);
			result.setNumero(numero);
			result.setWeight(weight);
			result.setOddAndEven(oddAndEven);
		} catch (NumberFormatException e) {
			log.error(ERROR_MSG, e);
		} catch (UnsupportedEncodingException e) {
			log.error(ERROR_MSG, e);
		}
		
		return result;
	}
	
	@Override
	@SuppressWarnings({"unchecked", "rawtypes"})
	public void sort(List<StreetBlockVO> list, final Integer type) {
		Collections.sort(list, new Comparator<StreetBlockVO>() {
			@Override
			public int compare(StreetBlockVO o1, StreetBlockVO o2) {
				Integer result = 0;
				Comparator comparator = Collator.getInstance(Locale.TRADITIONAL_CHINESE);
				//行政編號排序
				if (type == StreetBlockVO.TYPE_CITY) {
					result = o1.getAdm().substring(0, 4).compareTo(o2.getAdm().substring(0, 4));
				} else if (type == StreetBlockVO.TYPE_VILLAGE) {
					result = o1.getAdm().substring(0, 7).compareTo(o2.getAdm().substring(0, 7));
				} else {
					result = o1.getAdm().compareTo(o2.getAdm());
				}
				if (result == 0) {
					//路排序(照筆畫排序，而不按照ASCII CODE排序)
					result = comparator.compare(o1.getRoad(), o2.getRoad());
					if (result == 0) {
						//段排序
						result = comparator.compare(o1.getSectionCh(), o2.getSectionCh());
						if (result == 0) {
							//權重排序
							result = o1.getWeight().compareTo(o2.getWeight());
						}
					}
				}
				return result;
			}
		});
	}
	
	@Override
	public void output(List<StreetBlockVO> list, String url, String encoding,
			Integer type, Boolean addCommon) {
		this.sort(list, type);
		
		File file = new File(url);
		file.getParentFile().mkdirs();
		BufferedWriter bw = null;
		try {
			bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), encoding), BUFFER_SIZE);
			StreetBlockVO temp = null;
			String start = null;
			String end = null;
			Integer serial = 1;
			Integer count = 1;
			Boolean hasLane = false;
			Boolean hasAlley = false;
			Boolean hasSubAlley = false;
			
			for (int idx = 0; idx < list.size(); idx++) {
				StreetBlockVO vo = list.get(idx);
				
				if (temp == null) {
					//初始化
					temp = vo;
					start = vo.getNumero();
					end = vo.getNumero();
				}
				
				if (type == StreetBlockVO.TYPE_CITY) {
					if (!temp.getAdm().substring(0, 4).equals(vo.getAdm().substring(0, 4)) || !temp.getRoad().equals(vo.getRoad())) {
						//如果行政編號不相同或路不相同，則寫入到檔案，並增加序號
						String line = this.convertToString(temp, start, end, serial, count, hasLane, hasAlley, hasSubAlley, type, addCommon);
						bw.write(line);
						bw.newLine();
						
						temp = vo;
						start = vo.getNumero();
						end = vo.getNumero();
						hasLane = false;
						hasAlley = false;
						hasSubAlley = false;
						serial++;
						count++;
					}
				} else if (type == StreetBlockVO.TYPE_VILLAGE) {
					if (!temp.getAdm().substring(0, 7).equals(vo.getAdm().substring(0, 7)) || !temp.getRoad().equals(vo.getRoad())) {
						//如果行政編號不相同或路不相同，則寫入到檔案，並增加序號
						String line = this.convertToString(temp, start, end, serial, count, hasLane, hasAlley, hasSubAlley, type, addCommon);
						bw.write(line);
						bw.newLine();
						
						temp = vo;
						start = vo.getNumero();
						end = vo.getNumero();
						hasLane = false;
						hasAlley = false;
						hasSubAlley = false;
						serial++;
						count++;
					}
				} else {
					if (!temp.getAdm().equals(vo.getAdm()) || !temp.getRoad().equals(vo.getRoad())) {
						//如果行政編號不相同或路不相同，則寫入到檔案，並增加序號
						String line = this.convertToString(temp, start, end, serial, count, hasLane, hasAlley, hasSubAlley, type, addCommon);
						bw.write(line);
						bw.newLine();
						
						temp = vo;
						start = vo.getNumero();
						end = vo.getNumero();
						hasLane = false;
						hasAlley = false;
						hasSubAlley = false;
						serial++;
						count++;
					}
				}
				
				if ((type == StreetBlockVO.TYPE_NEIGHBORHOOD
						&& temp.getLaneCh().equals(vo.getLaneCh())
						&& temp.getAlleyCh().equals(vo.getAlleyCh())
						&& temp.getOddAndEven().equals(vo.getOddAndEven()))
						|| (type == StreetBlockVO.TYPE_NEIGHBORHOOD && !this.isEmpty(vo.getSubAlleyCh()))) {
					//如果都是同一條路段
					end = vo.getNumero();
				} else if (type != StreetBlockVO.TYPE_NEIGHBORHOOD
						&& temp.getLaneCh().equals(vo.getLaneCh())
						&& temp.getAlleyCh().equals(vo.getAlleyCh())
						&& temp.getSubAlleyCh().equals(vo.getSubAlleyCh())
						&& temp.getOddAndEven().equals(vo.getOddAndEven())) {
					//如果都是同一條路段
					end = vo.getNumero();
				} else {
					hasLane = false;
					hasAlley = false;
					hasSubAlley = false;
					
					if (temp.getRoad().equals(vo.getRoad())
							&& this.isEmpty(temp.getLaneCh())
							&& !this.isEmpty(vo.getLaneCh())
							&& this.checkOddAndEven(this.convertToInteger(temp.getNumero())) == this.checkOddAndEven(this.convertToInteger(vo.getLane()))) {
						//如果有巷子
						if (this.convertToInteger(vo.getLane()) < 5000) {
							end = vo.getLane();	
						}
						hasLane = true;
					}
					
					if (temp.getRoad().equals(vo.getRoad())
							&& temp.getLaneCh().equals(vo.getLaneCh())
							&& this.isEmpty(temp.getAlleyCh())
							&& !this.isEmpty(vo.getAlleyCh())
							&& this.checkOddAndEven(this.convertToInteger(temp.getNumero())) == this.checkOddAndEven(this.convertToInteger(vo.getAlley()))) {
						//如果有弄
						if (this.convertToInteger(vo.getAlley()) < 5000) {
							end = vo.getAlley();
						}
						hasAlley = true;
					}
					
					if (type != StreetBlockVO.TYPE_NEIGHBORHOOD 
							&& temp.getRoad().equals(vo.getRoad())
							&& temp.getLaneCh().equals(vo.getLaneCh())
							&& temp.getAlleyCh().equals(vo.getAlleyCh())
							&& this.isEmpty(temp.getSubAlleyCh())
							&& !this.isEmpty(vo.getSubAlleyCh())
							&& this.checkOddAndEven(this.convertToInteger(temp.getNumero())) == this.checkOddAndEven(this.convertToInteger(vo.getSubAlley()))) {
							//如果有衖
						if (this.convertToInteger(vo.getSubAlley()) < 5000) {
							end = vo.getSubAlley();
						}
						hasSubAlley = true;
					}
					
					String line = this.convertToString(temp, start, end, serial, count, hasLane, hasAlley, hasSubAlley, type, addCommon);

					//如果與條件不相同，則寫入檔案
					bw.write(line);
					bw.newLine();
					
					
					start = vo.getNumero();
					end = vo.getNumero();
					count++;
					temp = vo;
				}
				
				if (idx == list.size() - 1) {
					//如果是最後一筆資料，則寫入到檔案
					end = vo.getNumero();
					String line = this.convertToString(temp, start, end, serial, count, hasLane, hasAlley, hasSubAlley, type, addCommon);
					bw.write(line);
				}
			}
		} catch (UnsupportedEncodingException e) {
			log.error(ERROR_MSG, e);
		} catch (FileNotFoundException e) {
			log.error(ERROR_MSG, e);
		} catch (IOException e) {
			log.error(ERROR_MSG, e);
		} finally {
			try {
				if (bw != null) {
					bw.close();
				}
			} catch (IOException e) {
				log.error(ERROR_MSG, e);
			}
		}
	}
	
	@Override
	public String validate(String leftUrl, String rightUrl, String encoding, Integer type) {
		String path = rightUrl.substring(0, rightUrl.lastIndexOf("/")) + "/差異資料";
		String inFileName = null;
		String deFileName = null;
		String rsFileName = null;
		
		if (type == StreetBlockVO.TYPE_CITY) {
			inFileName = "/街廓(鄉鎮市區)差異(增加).txt";
			deFileName = "/街廓(鄉鎮市區)差異(減少).txt";
			rsFileName = "/驗證結果(鄉鎮市區).txt";
		} else if (type == StreetBlockVO.TYPE_VILLAGE) {
			inFileName = "/街廓(村里)差異(增加).txt";
			deFileName = "/街廓(村里)差異(減少).txt";
			rsFileName = "/驗證結果(村里).txt";
		} else {
			inFileName = "/街廓(鄰)差異(增加).txt";
			deFileName = "/街廓(鄰)差異(減少).txt";
			rsFileName = "/驗證結果(鄰).txt";
		}
		
		File inFile = new File(path + inFileName);
		inFile.getParentFile().mkdirs();
		File deFile = new File(path + deFileName);
		deFile.getParentFile().mkdirs();
		File rsFile = new File(path + rsFileName);
		rsFile.getParentFile().mkdirs();
		
		Map<String, String> table = new LinkedHashMap<String, String>();
		File leftFile = new File(leftUrl);
		File rightFile = new File(rightUrl);
		BufferedReader leftBr = null;
		BufferedReader rightBr = null;
		BufferedWriter inBw = null;
		BufferedWriter deBw = null;
		BufferedWriter rsBw = null;
		String result = null;
		
		try {
			leftBr = new BufferedReader(new InputStreamReader(new FileInputStream(leftFile), encoding), BUFFER_SIZE);
			rightBr = new BufferedReader(new InputStreamReader(new FileInputStream(rightFile), encoding), BUFFER_SIZE);
			inBw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(inFile), encoding), BUFFER_SIZE);
			deBw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(deFile), encoding), BUFFER_SIZE);
			rsBw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(rsFile), encoding), BUFFER_SIZE);
			
			Integer x = 0;
			if (type == StreetBlockVO.TYPE_CITY) {
				
			} else if (type == StreetBlockVO.TYPE_VILLAGE) {
				x = 71; 
			} else {
				x = 66; 
			}
			
			String line = null;
			while ((line = leftBr.readLine()) != null) {
				String str = line.substring(21, x);
				table.put(str.trim(), line);
			}
			Integer tableSize = table.size();
			Integer size = 0;
			Integer count = 0;
			while ((line = rightBr.readLine()) != null) {
				size++;
				String str = line.substring(21, x);
				if (table.containsKey(str.trim())) {
					table.remove(str.trim());
					count++;
				} else {
					inBw.write(line);
					inBw.newLine();
				}
			}
			line = null;
			
			Set<Entry<String, String>> tableSet = table.entrySet();
			for (Entry<String, String> entry : tableSet) {
				deBw.write(entry.getValue());
				deBw.newLine();
			}
			
			result = "比較對象筆數: " + tableSize + " 參考檔筆數: " + size + " 與比較對象相同筆數: " + count + " 相同率: " + 1.0 * count / tableSize;
			rsBw.write(result);
		} catch (UnsupportedEncodingException e) {
			log.error(ERROR_MSG, e);
		} catch (FileNotFoundException e) {
			log.error(ERROR_MSG, e);
		} catch (IOException e) {
			log.error(ERROR_MSG, e);
		} finally {
			try {
				if (leftBr != null) {
					leftBr.close();
				}
				if (rightBr != null) {
					rightBr.close();
				}
				if (inBw != null) {
					inBw.close();
				}
				if (deBw != null) {
					deBw.close();
				}
				if (rsBw != null) {
					rsBw.close();
				}
			} catch (IOException e) {
				log.error(ERROR_MSG, e);
			}
		}
		
		return result;
	}
	
	/**
	 * 補上全形空白
	 * @param str 字串
	 * @param size 長度
	 * @return String
	 */
	private String rightPadFW(String str, Integer size) {
		return StringUtils.rightPad(str, size, "　");
	}
	
	/**
	 * 補上半形空白
	 * @param str 字串
	 * @param size 長度
	 * @return String
	 */
	private String leftPad(String str, Integer size) {
		return StringUtils.leftPad(str, size, " ");
	}
	
	/**
	 * 將字串加入StringBuilder
	 * @param sb StringBuilder
	 * @param str String
	 * @param flag 是否需要補上分隔符號{true: 補上, false: 不補}
	 */
	private void append(StringBuilder sb, String str, Boolean flag) {
		sb.append(str);
		if (flag) {
			sb.append(",");
		}
	}
	
	/**
	 * 檢查單雙
	 * @param num 數字
	 * @return 0:沒資料, 1:單, 2:雙
	 */
	private Integer checkOddAndEven(Integer num) {
		if (num == 0) {
			return num;
		}
		if (num % 2 == 0) {
			return 2;
		}
		return 1;
	}

	/**
	 * 將字串轉換成整數
	 * @param str 字串
	 * @return 整數，如果是空字串則回傳0
	 */
	private Integer convertToInteger(String str) {
		if (!StringUtils.isEmpty(str)) {
			return Integer.parseInt(str);
		}
		return 0;
	}
	
	/**
	 * 將中文數字轉換成羅馬數字
	 * @param str 字串
	 * @return 羅馬數字
	 */
	private String formatChineseNumber(String str) {
		String[] numbers = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
		for (int idx = 0; idx < numbers.length; idx++) {
			if (numbers[idx].equals(str)) {
				return "" + (idx + 1);
			}
		}
		return "";
	}
	
	/**
	 * 將字串中的全形數字取出，並回傳半形數字
	 * @param str 字串
	 * @return 半形數字
	 */
	private String parseNumber(String str) {
		String regex = "[^\\d.]";
		StringBuilder sb = new StringBuilder();
		for (char ch : str.toCharArray()) {
			int code = ch;
			code -= 65248;
			sb.append((char) code);
		}
		return sb.toString().replaceAll(regex, "");
	}
	
	/**
	 * 檢查是否為空字串
	 * @param str 字串
	 * @return 是否為空字串{true: 是, false: 否}
	 */
	private Boolean isEmpty(String str) {
		for (char ch : str.toCharArray()) {
			int code = ch;
			if (code != 12288 && code != 32) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * 清除空白
	 * @param str 字串
	 * @return 字串
	 */
	private String trim(String str) {
		StringBuilder sb = new StringBuilder();
		for (char ch : str.toCharArray()) {
			int code = ch;
			if (code != 12288 && code != 32) {
				sb.append((char) code);
			}
		}
		return sb.toString();
	}
	
	/**
	 * 檢查是否有特殊
	 * @param str 字串
	 * @return 是否有特殊
	 */
	private Boolean hasSpecial(String str) {
		if (str.contains("之") || str.contains("橫")) {
			return true;
		} else if (!this.hasNumber(str)) {
			for (char ch : str.toCharArray()) {
				int code = ch;
				if (code != 12288 && code != 32) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * 檢查是否有數字
	 * @param str 字串
	 * @return 是否有數字{true: 是, false: 否}
	 */
	private Boolean hasNumber(String str) {
		String regex = ".*\\d+.*";
		if (!str.matches(regex)) {
			StringBuilder sb = new StringBuilder();
			for (char ch : str.toCharArray()) {
				int code = ch;
				code -= 65248;
				sb.append((char) code);
			}
			return sb.toString().matches(regex);
		}
		return str.matches(regex);
	}
	
	/**
	 * 轉換成字串
	 * @param vo StreetBlockVO
	 * @param start 開始號
	 * @param end 結束號
	 * @param serial 段序號
	 * @param count 編號
	 * @param hasLane
	 * @param hasAlley
	 * @param hasSubAlley
	 * @param type 以何種為界{1: 市(鄉鎮區), 2: 里(村), 3: 鄰}, StreetBlockVO有常數可使用
	 * @param addCommon 是否要加上分隔符號
	 * @return String
	 */
	private String convertToString(StreetBlockVO vo, String start,
			String end, Integer serial, Integer count, Boolean hasLane,
			Boolean hasAlley, Boolean hasSubAlley, Integer type, Boolean addCommon) {
		
		StringBuilder sb = new StringBuilder();
		if (!addCommon) {
			this.append(sb, this.leftPad("", 1), addCommon);
		}
		
		//縣(市)
		this.append(sb, this.rightPadFW(vo.getCounty(), 3), addCommon);
		//市(鄉鎮區)
		this.append(sb, this.rightPadFW(vo.getCity(), 4), addCommon);
		//里(村)
		this.append(sb, this.rightPadFW(vo.getVillage(), 4), addCommon);
		//路
		this.append(sb, this.rightPadFW(vo.getRoad(), 9), addCommon);
		
		//段(中文)
		this.append(sb, this.rightPadFW(vo.getSectionCh(), 6), addCommon);
		if (!this.isEmpty(vo.getSectionCh()) && !vo.getSectionCh().contains("村")) {
			this.append(sb, "段", addCommon);
		} else {
			this.append(sb, this.rightPadFW("", 1), addCommon);
		}
		
		//巷(中文)
		this.append(sb, this.rightPadFW(vo.getLaneCh(), 8), addCommon);
		if (!this.isEmpty(vo.getLaneCh()) && !vo.getLaneCh().contains("台化一莊")) {
			this.append(sb, "巷", addCommon);
		} else {
			this.append(sb, this.rightPadFW("", 1), addCommon);
		}
		
		//弄(中文)
		this.append(sb, this.rightPadFW(vo.getAlleyCh(), 6), addCommon);
		if (!this.isEmpty(vo.getAlleyCh())) {
			if (!vo.getAlleyCh().contains("橫")) {
				this.append(sb, "弄", addCommon);
			} else {
				this.append(sb, "巷", addCommon);
			}
		} else {
			this.append(sb, this.rightPadFW("", 1), addCommon);
		}
		
		if (type != StreetBlockVO.TYPE_NEIGHBORHOOD) {
			//衖(中文)
			this.append(sb, this.rightPadFW(vo.getSubAlleyCh(), 4), addCommon);
			
			if (!this.isEmpty(vo.getSubAlleyCh()) && !vo.getSubAlleyCh().contains("橫")) {
				this.append(sb, "衖", addCommon);
			} else {
				this.append(sb, this.rightPadFW("", 1), addCommon);
			}
		}
		
		if (!addCommon) {
			this.append(sb, this.leftPad("", 1), addCommon);
		}
		
		//行政編號
		this.append(sb, vo.getAdm().substring(0, 2), addCommon);
		this.append(sb, vo.getAdm().substring(2, 4), addCommon);
		
		if (type == StreetBlockVO.TYPE_CITY) {
			//市(鄉鎮區)
			this.append(sb, "***", addCommon);
			this.append(sb, "***", addCommon);
			this.append(sb, "***", addCommon);
		} else if (type == StreetBlockVO.TYPE_VILLAGE) {
			//里(村)
			this.append(sb, vo.getAdm().substring(4, 7), addCommon);
			this.append(sb, "***", addCommon);
			this.append(sb, "***", addCommon);
		} else {
			//鄰
			this.append(sb, vo.getAdm().substring(4, 7), addCommon);
			this.append(sb, vo.getAdm().substring(7, 10), addCommon);
			this.append(sb, "***", addCommon);
		}
		
		//起
		this.append(sb, this.leftPad(start, 4), addCommon);
		//迄
		this.append(sb, this.leftPad(end, 4), addCommon);
		//序號
		this.append(sb, this.leftPad(serial.toString(), 6), addCommon);
		//單雙
		if (!addCommon) {
			this.append(sb, this.leftPad("", 1), addCommon);
		}
		this.append(sb, vo.getOddAndEven().toString(), addCommon);
		
		//巷弄(數字)
		if (type == StreetBlockVO.TYPE_CITY) {
			//市(鄉鎮區)
			if (this.convertToInteger(vo.getLane()) != 0) {
				//如果是巷
				this.append(sb, this.leftPad(vo.getLane(), 4), addCommon);
				this.append(sb, this.leftPad(vo.getLane(), 4), addCommon);
				
				if (this.convertToInteger(vo.getAlley()) != 0) {
					//如果有弄
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						
						if (hasSubAlley || vo.getOddAndEven() != 1) {
							//如果是雙號
							this.append(sb, this.leftPad(end, 4), addCommon);
						} else {
							this.append(sb, this.leftPad(start, 4), addCommon);
						}
					}
				} else {
					//如果沒有弄
					this.append(sb, this.leftPad("0", 4), addCommon);
					if (hasAlley || vo.getOddAndEven() != 1) {
						//如果這條巷沒有弄或是雙號
						this.append(sb, this.leftPad(end, 4), addCommon);
					} else {
						this.append(sb, this.leftPad(start, 4), addCommon);
					}
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						this.append(sb, this.leftPad("0", 4), addCommon);
					}
				}
			} else {
				//如果不是巷
				this.append(sb, this.leftPad("0", 4), addCommon);
				if (hasLane || vo.getOddAndEven() != 1) {
					//如果這條路有巷或雙號
					this.append(sb, this.leftPad(end, 4), addCommon);
				} else {
					//如果是單號
					this.append(sb, this.leftPad(start, 4), addCommon);
				}
				if (this.convertToInteger(vo.getAlley()) != 0) {
					//如果沒巷有弄
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						
						if (hasSubAlley || vo.getOddAndEven() != 1) {
							//如果是雙號
							this.append(sb, this.leftPad(end, 4), addCommon);
						} else {
							this.append(sb, this.leftPad(start, 4), addCommon);
						}
					}
				} else {
					this.append(sb, this.leftPad("0", 4), addCommon);
					this.append(sb, this.leftPad("0", 4), addCommon);
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						this.append(sb, this.leftPad("0", 4), addCommon);
					}
				}
			}
		} else if (type == StreetBlockVO.TYPE_VILLAGE) {
			//里(村)
			if (this.convertToInteger(vo.getLane()) != 0) {
				//如果是巷
				this.append(sb, this.leftPad(vo.getLane(), 4), addCommon);
				this.append(sb, this.leftPad(vo.getLane(), 4), addCommon);
				
				if (this.convertToInteger(vo.getAlley()) != 0) {
					//如果有弄
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						
						if (hasSubAlley || vo.getOddAndEven() != 1) {
							//如果是雙號
							this.append(sb, this.leftPad(end, 4), addCommon);
						} else {
							this.append(sb, this.leftPad(start, 4), addCommon);
						}
					}
				} else {
					//如果沒有弄
					this.append(sb, this.leftPad("0", 4), addCommon);
					if (hasAlley || vo.getOddAndEven() != 1) {
						//如果這條巷沒有弄或是雙號
						this.append(sb, this.leftPad(end, 4), addCommon);
					} else {
						this.append(sb, this.leftPad(start, 4), addCommon);
					}
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						this.append(sb, this.leftPad("0", 4), addCommon);
					}
				}
			} else {
				//如果不是巷
				this.append(sb, this.leftPad("0", 4), addCommon);
				if (hasLane || vo.getOddAndEven() != 1) {
					//如果這條路有巷或雙號
					this.append(sb, this.leftPad(end, 4), addCommon);
				} else {
					//如果是單號
					this.append(sb, this.leftPad(start, 4), addCommon);
				}
				if (this.convertToInteger(vo.getAlley()) != 0) {
					//如果沒巷有弄
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						
						if (hasSubAlley || vo.getOddAndEven() != 1) {
							//如果是雙號
							this.append(sb, this.leftPad(end, 4), addCommon);
						} else {
							this.append(sb, this.leftPad(start, 4), addCommon);
						}
					}
				} else {
					this.append(sb, this.leftPad("0", 4), addCommon);
					this.append(sb, this.leftPad("0", 4), addCommon);
					
					if (this.convertToInteger(vo.getSubAlley()) != 0) {
						//如果有衖
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
						this.append(sb, this.leftPad(vo.getSubAlley(), 4), addCommon);
					} else {
						this.append(sb, this.leftPad("0", 4), addCommon);
						this.append(sb, this.leftPad("0", 4), addCommon);
					}
				}
			}
		} else {
			//鄰
			if (this.convertToInteger(vo.getLane()) != 0) {
				//如果是巷
				this.append(sb, this.leftPad(vo.getLane(), 4), addCommon);
				this.append(sb, this.leftPad(vo.getLane(), 4), addCommon);
				
				if (this.convertToInteger(vo.getAlley()) != 0) {
					//如果有弄
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
				} else {
					//如果沒有弄
					this.append(sb, this.leftPad("0", 4), addCommon);
					if (hasAlley) {
						//如果這條巷有弄
						this.append(sb, this.leftPad(end, 4), addCommon);
					} else {
						this.append(sb, this.leftPad(start, 4), addCommon);
					}
					
				}
			} else {
				//如果不是巷
				this.append(sb, this.leftPad("0", 4), addCommon);
				if (hasLane) {
					//如果這條路有巷
					this.append(sb, this.leftPad(end, 4), addCommon);
				} else {
					//如果這條路沒有巷
					this.append(sb, this.leftPad(start, 4), addCommon);
				}
				if (this.convertToInteger(vo.getAlley()) != 0) {
					//如果沒巷有弄
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
					this.append(sb, this.leftPad(vo.getAlley(), 4), addCommon);
				} else {
					this.append(sb, this.leftPad("0", 4), addCommon);
					this.append(sb, this.leftPad("0", 4), addCommon);
				}
			}
		}
		
		//段(數字)
		if (!addCommon) {
			this.append(sb, this.leftPad("", 1), addCommon);
		}
		this.append(sb, this.leftPad(vo.getSection(), 6), addCommon);
		//編號
		this.append(sb, this.leftPad(count.toString(), 10), addCommon);
		return sb.toString();
	}

}
